#include "Primitives.h"

Primitive::Primitive(){}

Primitive::Primitive(const Material& _m) : m(_m) {}

double Primitive::transparency() const {
	return m.transparency;
}

double Primitive::reflection() const {
	return m.reflection;
}

double Primitive::specular_reflection() const {
	return m.specular_reflection;
}

double Primitive::diffuse_reflection() const {
	return m.diffuse_reflection;
}

double Primitive::shininess() const {
	return m.shininess;
}

double Primitive::refraction() const {
	return m.refraction;
}

double Primitive::ior() const {
	return m.ior;
}

Color Primitive::color() const {
	return m.color;
}

Sphere::Sphere(){}

Sphere::Sphere(const Vector& _c, const double& _r, const Material& m) : Primitive(m), r(_r), c(_c){}

hitResult Sphere::intersects(const Ray& i, const double& max_d) const {

	hitResult res;
	res.hit = false;

	// coeficientes de la ecuacion cuadratica
	double A = i.direction*i.direction;
	double B = (i.origin-c)*2*i.direction;
	double C = (i.origin-c)*(i.origin-c)-r*r;

	// calculo el discriminante
	double disc = B*B - 4*A*C;

	// me fijo que sea positivo
	if(disc<0) return res;

	// calculo las soluciones
	double s = sqrtf(disc);
	double t0 = (-B - s)/2;
	double t1 = (-B + s)/2;

	if( 0<t0 || 0<t1 ){

		if( t1 < t0 ){
			double temp = t0;
			t0 = t1;
			t1 = temp;
		}

		res.hit = true;

		if(t0<0){
//			cout << "QUE COÑO?" << endl;
			assert(0<=t1);
			res.distance = t1;
		}else{
//			cout << "UNO BIEEEEEEEEEEN" << endl;
			assert(0<=t0);
			res.distance = t0;
		}

	}else{

//		cout << "AL HORNO!" << endl;

		return res;
	
	}
}

Vector Sphere::normal(const Vector& p) const {
	return (p-c).normalize();
}

Ray Sphere::refraction(const Vector& i, const Vector& d) const {

	/* Calculo la primera refraccion */

	Ray r1;
	r1.origin = i;

	r1.direction = d.refract(normal(r1.origin),1.0,ior());

	r1.origin = r1.origin + r1.direction*0.001;

	/* Calculo la segunda refraccion */

	Ray r2;

	hitResult i2 = intersects(r1,INFINITY);

	if(i2.hit){

		r2.origin = r1.origin + r1.direction*i2.distance;
		r2.direction = d.refract(normal(r2.origin)*-1,ior(),1.0);

		return r2;

		//cout << "FUNCA";

	}else{

		//cout << "CACA";

	}

	return r1;

}

Plane::Plane(){}

Plane::Plane(const Vector& _n, const double& _d, const Material& m) : Primitive(m), n(_n), d(_d) {}

hitResult Plane::intersects(const Ray& i, const double& max_d) const{
	hitResult res;
	res.hit = false;
	double cos = n*i.direction;
	// si no son perpendiculares = si no es paralelo al plano
	if(cos!=0){
		float dist = (n*i.origin + d) / cos;
		// si no esta atras de la camara
		if( 0 < dist && dist < max_d ){
			res.hit = true;
			res.distance = dist;
		}
	}
	return res;
}

Vector Plane::normal(const Vector& p) const{
	return n;
}

Ray Plane::refraction(const Vector& i, const Vector& d) const {
	
}

